﻿using MvcWechat.Cryptography;
using MvcWechat.Models;
using MvcWechat.Services;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Text;
using System.Threading;
using System.Web.Mvc;
using MvcWechat.Common;

namespace MvcWechat.Controllers
{
    public class HomeController : Controller
    {

        /// <summary>
        /// 微信后台验证地址（使用Get），微信后台的“接口配置信息”的Url  
        /// </summary>
        [HttpGet]
        [ActionName("Index")]
        public ActionResult Get(string signature, string timestamp, string nonce, string echostr)
        {
            ConfigSettings config = CommonPage.GetConfigSettings();
            var xml = @"<xml><ToUserName><![CDATA[gh_a1ed23e0fcb0]]></ToUserName>
                    <FromUserName><![CDATA[ow1uIwdFzpSPLcHGy5jzRt118lkI]]></FromUserName>
                    <CreateTime>1505544519</CreateTime>
                    <MsgType><![CDATA[event]]></MsgType>
                    <Event><![CDATA[subscribe]]></Event>
                    <EventKey><![CDATA[]]></EventKey>
                    </xml>";
            var message = AcceptMessageAPI.Parse(xml);

            Logger.Info(this.GetType(), string.Format("Get:{0}\n{1}\n{2}\n{3}\n{4}", this.Request.Url, signature, timestamp, nonce, echostr));

            var token = config.Token;//微信公众平台后台设置的Token
            if (string.IsNullOrEmpty(token)) return Content("请先设置Token！");
            var ent = "";
            if (!BasicAPI.CheckSignature(signature, timestamp, nonce, token, out ent))
            {
                return Content("访问出错");
            }
            return Content(echostr); //返回随机字符串则表示验证通过
        }

 

        [HttpGet]
        public ActionResult TestWx(string signature, string timestamp, string nonce, string echostr)
        {
            //GetAccessToken code:0619SOXf0vKuGB1WDOUf0QEpXf09SOXA,appId:,appSecret:0619SOXf0vKuGB1WDOUf0QEpXf09SOXA
           // var a= OAuth2API.GetAccessToken("0619SOXf0vKuGB1WDOUf0QEpXf09SOXA", "0619SOXf0vKuGB1WDOUf0QEpXf09SOXA", "0619SOXf0vKuGB1WDOUf0QEpXf09SOXA");
            var xml = "{\"access_token\":\"d-wUZviDAleLQKOho4n9d2mpMBQrmrclGUN3PFYrcyeDdrQ5Kmos8KhACkKs4lg1USujOwoHzT_7ymSjwGO_1w\",\"expires_in\":7200,\"refresh_token\":\"s8-3YazZYfr-2svkP8NpZ0chd3-HAr382KlzPE7KhbeCqkP4YAMysHI06QjAmeYTxKnC4WdWlg-LjbbrJFywvA\",\"openid\":\"ow1uIwdFzpSPLcHGy5jzRt118lkI\",\"scope\":\"snsapi_userinfo\"}";
            var a = DynamicJson.Parse(xml);
            var message = AcceptMessageAPI.Parse(xml);
            var response = new WeixinExecutor().Execute(message);

            var encryptMsg = string.Empty;
 

            return new ContentResult
            {
                Content = encryptMsg,
                ContentType = "text/xml",
                ContentEncoding = System.Text.UTF8Encoding.UTF8
            };
        }
        [HttpPost]
        public ActionResult Index(string signature, string timestamp, string nonce, string echostr)
        {
            try
            {
                ConfigSettings config = CommonPage.GetConfigSettings();
                Logger.Error(this.GetType(), string.Format("signature:{0},timestamp{1},nonce:{2},echostr:{3}", signature, timestamp, nonce, echostr));
                //用户回复信息,或者点击事件
                WeixinMessage message = null;
                var safeMode = Request.QueryString.Get("encrypt_type") == "aes";  //公众号无加密encrypt_type返回空，echostr Post为空
                var decryptMsg = string.Empty;
                Logger.Error(this.GetType(), 1);
                using (var streamReader = new StreamReader(Request.InputStream))
                {
                    Logger.Error(this.GetType(), 2);
                    var msg = streamReader.ReadToEnd();
                    #region 解密
                    if (safeMode)
                    {
                        var msg_signature = Request.QueryString.Get("msg_signature");
                        var wxBizMsgCrypt = new WXBizMsgCrypt(config.Token, config.EncodingAESKey, config.AppIDByWX);
                        var ret = wxBizMsgCrypt.DecryptMsg(msg_signature, timestamp, nonce, msg, ref decryptMsg);
                        if (ret != 0)//解密失败
                        {
                            //TODO：开发者解密失败的业务处理逻辑
                            //注意：本demo用log4net记录此信息，你可以用其他方法
                            Logger.Error(this.GetType(), string.Format("decrypt message return {0}, request body {1}", ret, msg));
                        }
                    }
                    else
                    {
                        decryptMsg = msg;
                    }
                    #endregion

                    message = AcceptMessageAPI.Parse(decryptMsg);  //decryptMsg: array to string
                }
                Logger.Error(this.GetType(), string.Format("response body {0}", decryptMsg));
                var response = new WeixinExecutor().Execute(message);

                var encryptMsg = string.Empty;

                #region 加密
                if (safeMode)
                {
                    var msg_signature = Request.QueryString.Get("msg_signature");
                    var wxBizMsgCrypt = new WXBizMsgCrypt(config.Token, config.EncodingAESKey, config.AppIDByWX);
                    var ret = wxBizMsgCrypt.EncryptMsg(response, timestamp, nonce, ref encryptMsg);
                    if (ret != 0)//加密失败
                    {
                        //TODO：开发者加密失败的业务处理逻辑
                        Logger.Error(this.GetType(), string.Format("encrypt message return {0}, response body {1}", ret, response));
                    }

                }
                else
                {
                    encryptMsg = response;
                }
                #endregion

                return new ContentResult
                {
                    Content = encryptMsg,
                    ContentType = "text/xml",
                    ContentEncoding = System.Text.UTF8Encoding.UTF8
                };
            }
            catch (Exception ex)
            {
                Log(ex.ToString());
                throw;
            }

        }


        private void Log(string msg, int i = -1)
        {
            var t = this.GetType();
            switch (i)
            {
                case -1: log4net.LogManager.GetLogger(t).Debug(msg); break;
                case 0: log4net.LogManager.GetLogger(t).Info(msg); break;
                case 1: log4net.LogManager.GetLogger(t).Warn(msg); break;
                case 2: log4net.LogManager.GetLogger(t).Error(msg); break;
                case 3: log4net.LogManager.GetLogger(t).Fatal(msg); break;
            }
        }
        StringBuilder sb = new StringBuilder();
        const string sIdx = "Table_map: `eegia`";
        const string eIdx = "BEGIN";
        public string GetSql() {
            var path =Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"Views//");
            //var sqlTxtAll = "";
            //for (int i = 0; i < 4; i++)
            //{
            //    var sqlTxt=System.IO.File.ReadAllText(path+"Home/sqlall"+i+".txt");
            //    sqlTxtAll += TirmTxt(sqlTxt);
            //} 
            //System.IO.File.WriteAllText(path + "Home/sql2.txt", sqlTxtAll);
            //return sqlTxtAll;

            List<string> lastLineList = new List<string>();
            int logCount = 0;
            int isStart = 0;
            new Thread((ThreadStart)delegate
            {
                StreamReader sr = new StreamReader(path + "Home/sql.log", Encoding.GetEncoding("utf-8"));
                while (true)
                {
                    logCount++;
                    if (logCount%100==0)
                        Log("logCount"+(logCount++).ToString(), 3);
                    string line = sr.ReadLine();
                    if (line == null)
                    {
                        Log("logCount" + (logCount++).ToString(), 3);
                        System.IO.File.WriteAllText(path + "Home/eegia27.txt", sb.ToString());
                        break;
                    }
                    lastLineList.Add(line);
                    if (line.Contains(sIdx))
                    {
                        isStart = 1;
                        //加入目标值前三行;
                        sb.AppendLine(lastLineList[lastLineList.Count - 4]);
                        sb.AppendLine(lastLineList[lastLineList.Count - 3]);
                        sb.AppendLine(lastLineList[lastLineList.Count - 2]);
                        lastLineList = new List<string>();
                    } 
                    if (line.Contains(eIdx))
                    {
                        isStart = 0;
                    }
                    if (isStart > 0)
                        sb.AppendLine(line);
                }
            }).Start();
            Log("over : "+sb.Length.ToString(), 1);
           
            return "ok";
        }  





      
        string partStr = "";//剩下的部分
        int i = 0;
        public string TirmTxt(string txt)
        {
            try
            {
                GC.Collect();
                partStr = txt;
                string sTxt = "";
                string eTxt = "";
                if (txt.IndexOf(sIdx) > -1) //避免加入
                {
                    i++;
                    sTxt = partStr.Substring(0, partStr.IndexOf(sIdx) - 89);  //找到开始指定前的部分
                    //加入除指定匹配的两字符串外的部分
                    if (sTxt != "")  //replace 时字符串长度不能为0
                        partStr = partStr.Replace(sTxt, ""); //过滤已处理的部分
                    if (partStr.IndexOf(eIdx, 1) > -1) //要有第二个eIdx才加入
                    {
                        eTxt = partStr.Substring(0, partStr.IndexOf(eIdx, 1)); //找到开始指定的两个字符间的部分
                        sb.Append(eTxt);
                        partStr = partStr.Replace(eTxt, ""); //过滤已处理的部分
                    }
                }
                if (partStr.Contains(sIdx))
                {
                    Thread.Sleep(40);
                    Logger.Debug(this.GetType(), "I:" + i);
                    TirmTxt(partStr); //如果还包含指定字符则继续递归匹配加入
                }
                else
                {
                    sb.Append(partStr); //添加最后的部分
                }
            }
            catch (Exception ex)
            {
                Logger.Debug(this.GetType(), "ex I:" + i);
                throw ex;
            }
           
            return sb.ToString();
        }
        //const string sIdx = "BINLOG '";
        //const string eIdx = "'/*!*/;";
        //string partStr = "";//剩下的部分
        //public string TirmTxt(string txt) {
        //    partStr=txt;
        //    string sTxt ="";
        //    string eTxt ="";
        //    if (txt.IndexOf(sIdx) > -1) //避免加入
        //    {
        //        sTxt = partStr.Substring(0, partStr.IndexOf(sIdx));  //找到开始指定前的部分
        //        sb.Append(sTxt);  //加入除指定匹配的两字符串外的部分
        //        partStr = partStr.Replace(sTxt, ""); //过滤已处理的部分
        //        eTxt = partStr.Substring(0, partStr.IndexOf(eIdx) + eIdx.Length); //找到开始指定的两个字符间的部分
        //        partStr = partStr.Replace(eTxt, ""); //过滤已处理的部分
        //    }
        //    if (partStr.Contains(sIdx))
        //    {
        //        TirmTxt(partStr); //如果还包含指定字符则继续递归匹配加入
        //    }
        //    else {
        //        sb.Append(partStr); //添加最后的部分
        //    }
        //    return sb.ToString();
        //}

        private const string TXT_FILE_PATH =  "E://Views//Home/sql.log";
        private const string SPLIT_VARCHAR = "囧";
        private const char SPLIT_CHAR = '囧';
        private static long FILE_SIZE = 0;
        static void Main(string[] args)
        {
            //long ttargetRowNum = 39999999;
            long ttargetRowNum = 10000000;
            DateTime beginTime = DateTime.Now;
            string line = CreateMemoryMapFile(ttargetRowNum);
            double totalSeconds = DateTime.Now.Subtract(beginTime).TotalSeconds;
            Console.WriteLine(line);
            Console.WriteLine(string.Format("查找第{0}行,共耗时:{1}s", ttargetRowNum, totalSeconds));
            Console.ReadLine();
        }

        /// <summary>
        /// 创建内存映射文件
        /// </summary>
        private static string CreateMemoryMapFile(long ttargetRowNum)
        {
            string line = string.Empty;
            using (FileStream fs = new FileStream(TXT_FILE_PATH, FileMode.Open, FileAccess.ReadWrite))
            {
                long targetRowNum = ttargetRowNum + 1;//目标行
                long curRowNum = 1;//当前行
                FILE_SIZE = fs.Length;
                using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(fs, "test", fs.Length, MemoryMappedFileAccess.ReadWrite, null, HandleInheritability.None, false))
                {
                    long offset = 0;
                    //int limit = 250;
                    int limit = 200;
                    try
                    {
                        StringBuilder sbDefineRowLine = new StringBuilder();
                        do
                        {
                            long remaining = fs.Length - offset;
                            using (MemoryMappedViewStream mmStream = mmf.CreateViewStream(offset, remaining > limit ? limit : remaining))
                            //using (MemoryMappedViewStream mmStream = mmf.CreateViewStream(offset, remaining))
                            {
                                offset += limit;
                                using (StreamReader sr = new StreamReader(mmStream))
                                {
                                    //string ss = sr.ReadToEnd().ToString().Replace("\n", "囧").Replace(Environment.NewLine, "囧");
                                    string ss = sr.ReadToEnd().ToString().Replace("\n", SPLIT_VARCHAR).Replace(Environment.NewLine, SPLIT_VARCHAR);
                                    if (curRowNum <= targetRowNum)
                                    {
                                        if (curRowNum < targetRowNum)
                                        {
                                            string s = sbDefineRowLine.ToString();
                                            int pos = s.LastIndexOf(SPLIT_CHAR);
                                            if (pos > 0)
                                                sbDefineRowLine.Remove(0, pos);

                                        }
                                        else
                                        {
                                            line = sbDefineRowLine.ToString();
                                            return line;
                                        }
                                        if (ss.Contains(SPLIT_VARCHAR))
                                        {
                                            curRowNum += GetNewLineNumsOfStr(ss);
                                            sbDefineRowLine.Append(ss);
                                        }
                                        else
                                        {
                                            sbDefineRowLine.Append(ss);
                                        }
                                    }
                                    //sbDefineRowLine.Append(ss);
                                    //line = sbDefineRowLine.ToString();
                                    //if (ss.Contains(Environment.NewLine))
                                    //{
                                    //    ++curRowNum;
                                    //    //curRowNum++;
                                    //    //curRowNum += GetNewLineNumsOfStr(ss);
                                    //    //sbDefineRowLine.Append(ss);
                                    //}
                                    //if (curRowNum == targetRowNum)
                                    //{
                                    //    string s = "";
                                    //}

                                    sr.Dispose();
                                }

                                mmStream.Dispose();
                            }
                        } while (offset < fs.Length);
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e.Message);
                    }
                    return line;
                }
            }
        }

        private static long GetNewLineNumsOfStr(string s)
        {
            string[] _lst = s.Split(SPLIT_CHAR);
            return _lst.Length - 1;
        }
    }
}
